#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include <vector>
#include <functional>
#include <unistd.h>

pthread_mutex_t MTX = PTHREAD_MUTEX_INITIALIZER; // 线程池互斥锁

class ThreadPool
{
public:
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_q_mtx);
        pthread_cond_destroy(&_cond);
        delete _instance;
        _instance = nullptr;
    }

    static ThreadPool *GetSInstance()
    {
        if(_instance == nullptr)
        {
            pthread_mutex_lock(&MTX);
            if(_instance == nullptr)
                _instance = new ThreadPool();
            pthread_mutex_unlock(&MTX);
        }
        return _instance;
    }

    void Start() // 开启线程池
    {
        for(int i = 0; i < _thread_num; i++)
        {
            pthread_create(&_pid[i], nullptr, Routine, this);
        }
        std::cout << "线程池启动成功" << std::endl;
    }

public:
    void Push(int task)
    {
        pthread_mutex_lock(&_q_mtx);
        _q.push(task);
        pthread_cond_signal(&_cond); // 唤醒线程处理任务
        pthread_mutex_unlock(&_q_mtx);
    }

    void Pop(int* task)
    {
        pthread_mutex_lock(&_q_mtx);
        while(_q.empty()) pthread_cond_wait(&_cond, &_q_mtx);
        *task = _q.front(); _q.pop();
        pthread_mutex_unlock(&_q_mtx);
    }

private:
    static void* Routine(void* args) // args=this
    {
        while(1)
        {
            ThreadPool* tp = (ThreadPool*)args;
            int task;
            tp->Pop(&task);
            std::cout << "run:" << task <<std::endl;
            sleep(5);
        }
        return nullptr;
    }

private:
    ThreadPool(int thread_num = 5)
    :_thread_num(thread_num), _pid(thread_num)
    {
        pthread_mutex_init(&_q_mtx, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;

private:
    static ThreadPool * _instance; // 单例对象
    int _thread_num; // 线程数量
    std::queue<int> _q; // 任务队列
    pthread_mutex_t _q_mtx; // 队列互斥锁
    pthread_cond_t _cond; // 条件变量
    std::vector<pthread_t> _pid; // 存储线程id
};

ThreadPool * ThreadPool::_instance = nullptr; // 单例对象